package com.lianyi.push.share.tcpclient;

import android.content.Context;
import android.text.TextUtils;

import com.lianyi.push.entity.TcpMsgBean;
import com.lianyi.push.share.ConstantValue;
import com.lianyi.push.share.NettyConfig;
import com.lianyi.push.share.channelinitializer.TcpClientChannelInitializer;
import com.lianyi.push.share.listener.TcpSeiviceToClientMessageListener;
import com.lianyi.push.util.CommonUtils;
import com.lianyi.push.util.LogUtil;
import com.lianyi.push.util.Preconditions;
import com.lianyi.push.util.SPTcpUtils;
import com.lianyi.push.util.SPTcpUtilsName;

import org.json.JSONException;
import org.json.JSONObject;

import java.net.InetSocketAddress;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;

/**
 * Created by leilei on 2018/4/4.
 */

public class TcpClient {
    private ExecutorService executorService = Executors.newFixedThreadPool(ConstantValue.TCP_MAX_COUNT);
    public static ConcurrentHashMap<String, String> hashMap = new ConcurrentHashMap<>();//记录是否连接成功
    public static ConcurrentHashMap<String, Integer> hashMapCount = new ConcurrentHashMap<>();//记录TCP连接失败重连次数
    private Context mContext;
    private int count = 3;
    private TcpSeiviceToClientMessageListener tcpSeiviceToClientMessageListener;

    private TcpClient() {
    }

    public void init(Context context) {
        this.mContext = context;
    }

    public void setOntcpSeiviceToClientMessageListener(TcpSeiviceToClientMessageListener listener) {
        tcpSeiviceToClientMessageListener = listener;
    }

    private static class SingletonHolder {
        private static final TcpClient INSTANCE = new TcpClient();
    }

    public static TcpClient getInstance() {
        return SingletonHolder.INSTANCE;
    }

    public synchronized void StartTcpClient(String ip_all, TcpSeiviceToClientMessageListener listener) {
        Preconditions.checkNotNull(mContext, "TcpClient StartTcpClient Context isNull");
        Preconditions.checkNotNull(ip_all, "TcpClient StartTcpClient ip_all isNull");
        this.tcpSeiviceToClientMessageListener = listener;
        if (CommonUtils.Available(mContext)) {
            if (!TextUtils.isEmpty(ip_all)) {
                final String[] array = ip_all.split(",");
                for (int i = 0; i < array.length; i++) {
                    final int finalI = i;
                    executorService.execute(new Runnable() {
                        @Override
                        public void run() {
                            Iterator iterator = hashMap.entrySet().iterator();
                            while (iterator.hasNext()) {
                                Map.Entry entry = (Map.Entry) iterator.next();
                                String key = (String) entry.getKey();
                                String value = (String) entry.getValue();
                                LogUtil.e("键值对", key + "||" + value);
                                if (key.contains(array[finalI]) && value.equals("true")) {
                                    array[finalI] = "";
                                }
                            }
                            String hostIp = array[finalI];
                            if (!TextUtils.isEmpty(hostIp) /*&& array[finalI].contains("192") */ && !hostIp.contains(CommonUtils.getLocalIpAddress())) {
                                LogUtil.e("连接的IP地址", hostIp + "==");
                                hashMapCount.put(hostIp, 0);//初始化TCP连接失败重连次数为0
                                TcpClient.getInstance().connect(hostIp);
                            }
                        }
                    });
                }
            } else {
                LogUtil.e("TcpClient发送ip为空", "TcpClient发送ip为空");
            }
        }
    }


    /**
     * 连接服务端
     *
     * @param hostname 连接地址
     */
    public void connect(String hostname) {
        Preconditions.checkNotNull(mContext, "TcpClient Context isNull");
        Preconditions.checkNotNull(hostname, "TcpClient hostname isNull");
        if (CommonUtils.Available(mContext)) {
            EventLoopGroup group = null;
            try {
                group = new NioEventLoopGroup();
                Bootstrap b = new Bootstrap();//创建Bootstrap
                b.group(group)
                        .channel(NioSocketChannel.class)
                        .option(ChannelOption.TCP_NODELAY, true)//是否禁用nagle算法,true为禁用
                        .option(ChannelOption.SO_KEEPALIVE, true)//保持长连接
                        .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000)//连接超时毫秒数，默认值30000毫秒即30秒
                        .handler(new LoggingHandler(LogLevel.INFO))
                        .remoteAddress(new InetSocketAddress(hostname, ConstantValue.TCP_PORT))
//                        .handler(new ChannelInitializer<SocketChannel>() {
//                            @Override
//                            protected void initChannel(SocketChannel ch) throws Exception {
////                                ch.pipeline().addLast(new IdleStateHandler(0, 4, 0, TimeUnit.SECONDS));
////                                ch.pipeline().addLast(new SmartCarEncoder());
////                                ch.pipeline().addLast(new SmartCarDecoder());
////                                ch.pipeline().addLast(new ClientHandler(mContext));
//                                ch.pipeline().addLast(new ObjectDecoder(1024 * 1024 * 1024,
//                                        ClassResolvers.weakCachingConcurrentResolver(this.getClass().getClassLoader())));
//                                ch.pipeline().addLast(new ObjectEncoder());
//                                ch.pipeline().addLast(new TcpClientHandler(mContext));
//                            }
//                        })
                        .handler(new TcpClientChannelInitializer(mContext, tcpSeiviceToClientMessageListener))
                ;
                ChannelFuture channelFuture = b.connect().sync();//连接到远程节点,阻塞等待直到连接完成
                if (channelFuture.isSuccess()) {
                    LogUtil.e("远程节点启动成功", "远程节点启动成功:" + hostname);
                    hashMap.put(hostname, "true");
                    hashMapCount.put(hostname, 0);//初始化TCP连接失败重连次数为0
                } else {
                    hashMap.put(hostname, "false");
                    LogUtil.e("远程节点启动失败", "远程节点启动失败:" + hostname);
                }
                channelFuture.channel().closeFuture().sync();//阻塞，直到Channel关闭
            } catch (InterruptedException e) {
                hashMap.put(hostname, "false");
                LogUtil.e("与服务器连接失败", "与服务器连接失败:" + hostname);
            } catch (Exception e) {
                LogUtil.e("与服务器连接失败抛出异常", "与服务器连接失败抛出异常:" + hostname + "异常原因:" + e);
                String isConnect = hashMap.get(hostname);
                if (TextUtils.isEmpty(isConnect)) {
                    isConnect = "false";
                }
                if (hashMapCount.get(hostname) != null) {
                    count = hashMapCount.get(hostname);
                }
                if (count < ConstantValue.TCP_CONNECT_AGAIN && isConnect.equals("false")) {
                    count++;
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e1) {
                        e1.printStackTrace();
                    }
                    LogUtil.e("countcount==", count + "==");
                    hashMapCount.put(hostname, count);
                    TcpClient.getInstance().reconnection(hostname);
                }
            } finally {
                if (group != null) {
                    group.shutdownGracefully();//关闭线程池并且释放所有的资源
                }
            }
        }
    }

//    public void SendMessage(String massage) {
//        Preconditions.checkNotNull(massage, "TcpClient hostname isNull");
//        if (CommonUtils.Available(mContext)) {
//            String data = massage.toString();
//            byte[] content = data.getBytes();
//            int contentLength = content.length;
//            SmartCarProtocol protocol = new SmartCarProtocol(contentLength, content);
//            NettyConfig.client_group.writeAndFlush(protocol);
//        }
//    }

    /**
     * 客户端发送消息给已经连接的服务端
     *
     * @param tcpMsgBean
     */
    public void SendMessage(TcpMsgBean tcpMsgBean) {
        Preconditions.checkNotNull(tcpMsgBean, "TcpClient SendMessage massage isNull");
        if (CommonUtils.Available(mContext)) {
            NettyConfig.client_group.writeAndFlush(tcpMsgBean);
        }
    }

    /**
     * 获取连接状态
     *
     * @param hostname
     * @return
     */
    public boolean isConnect(String hostname) {
        Preconditions.checkNotNull(hostname, "TcpClient isConnect hostname isNull");
        Iterator iterator = hashMap.entrySet().iterator();
        boolean isconnect = false;
        while (iterator.hasNext()) {
            Map.Entry entry = (Map.Entry) iterator.next();
            String key = (String) entry.getKey();
            String value = (String) entry.getValue();
            LogUtil.e("键值对", key + "||" + value);
            if (key.contains(hostname) && value.equals("true")) {
                isconnect = true;
            } else {
                isconnect = false;
            }
        }
        return isconnect;
    }

    /**
     * 连接所有服务端
     */
    public void sendAllIpAndStartTcpClient() {
        Preconditions.checkNotNull(mContext, "TcpClient sendAllIpAndStartTcpClient Context isNull");
        if (CommonUtils.Available(mContext)) {
            String all_ip = SPTcpUtils.getInstance(SPTcpUtilsName.TCP_TABLE).getString(SPTcpUtilsName.TCP_IP_ALL);
            if (!TextUtils.isEmpty(all_ip)) {
                try {
                    JSONObject jsonObject = new JSONObject(all_ip);
                    Iterator<String> iterator = jsonObject.keys();
                    while (iterator.hasNext()) {
                        String key = iterator.next();
                        TcpClient.getInstance().StartTcpClient(key, tcpSeiviceToClientMessageListener);
//                        TcpClient.getInstance().reconnection(key);
//                    boolean value = jsonObject.getBoolean(key);
                    }
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 发送数据给主机
     *
     * @param tcpMsgBean
     */
    public void sendMainIpAndStartTcpClient(TcpMsgBean tcpMsgBean) {
        Preconditions.checkNotNull(mContext, "TcpClient sendMainIpAndStartTcpClient Context isNull");
        Preconditions.checkNotNull(tcpMsgBean, "TcpClient sendMainIpAndStartTcpClient TcpMsgBean isNull");
        if (CommonUtils.Available(mContext)) {
            String all_ip = SPTcpUtils.getInstance(SPTcpUtilsName.TCP_TABLE).getString(SPTcpUtilsName.TCP_IP_ALL);
            try {
                JSONObject jsonObject = new JSONObject(all_ip);
                Iterator<String> iterator = jsonObject.keys();
                while (iterator.hasNext()) {
                    String key = iterator.next();
                    boolean value = jsonObject.optBoolean(key);
                    if (!TextUtils.isEmpty(value + "") && value) {
                        LogUtil.e("TcpClient连接的ip2", key + "==");
                        TcpClient.getInstance().StartTcpClient(key, tcpSeiviceToClientMessageListener);
//                        TcpClient.getInstance().reconnection(key);
                        TcpClient.getInstance().SendMessage(tcpMsgBean);
                    }
                }
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 存入连接的IP地址
     *
     * @param date
     * @param flag
     */
    public void putAllIp(String date, boolean flag) {
        Preconditions.checkNotNull(mContext, "TcpClient putAllIp Context isNull");
        if (CommonUtils.Available(mContext)) {
            if (!TextUtils.isEmpty(date) && !TextUtils.isEmpty(flag + "")) {
                String all_ip = SPTcpUtils.getInstance(SPTcpUtilsName.TCP_TABLE).getString(SPTcpUtilsName.TCP_IP_ALL);
                if (!TextUtils.isEmpty(all_ip)) {
                    try {
                        JSONObject jsonObject = new JSONObject(all_ip);
                        jsonObject.put(date, flag);
                        SPTcpUtils.getInstance(SPTcpUtilsName.TCP_TABLE).put(SPTcpUtilsName.TCP_IP_ALL, jsonObject.toString());
//                        LogUtil.e("TcpClient存入的ip1", jsonObject.toString() + "==");
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                } else {
                    try {
                        JSONObject jsonObject = new JSONObject();
                        jsonObject.put(date, flag);
                        SPTcpUtils.getInstance(SPTcpUtilsName.TCP_TABLE).put(SPTcpUtilsName.TCP_IP_ALL, jsonObject.toString());
//                        LogUtil.e("TcpClient存入的ip2", jsonObject.toString() + "==");
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                }

            }
        }
    }

    /**
     * 清除连接的IP地址
     *
     * @param date
     */
    public void removeAllIp(String date) {
        Preconditions.checkNotNull(mContext, "TcpClient removeAllIp mContext isNull");
        if (CommonUtils.Available(mContext)) {
            String all_ip = SPTcpUtils.getInstance(SPTcpUtilsName.TCP_TABLE).getString(SPTcpUtilsName.TCP_IP_ALL);
            if (!TextUtils.isEmpty(all_ip)) {
                try {
                    JSONObject jsonObject = new JSONObject(all_ip);
                    if (!TextUtils.isEmpty(date)) {
                        if (jsonObject.has(date)) {
                            jsonObject.remove(date);
                            TcpClient.getInstance().disconnect(date);
                            if (jsonObject.length() > 0) {
                                Iterator<String> iterator = jsonObject.keys();
                                while (iterator.hasNext()) {
                                    String key = iterator.next();
                                    boolean value = jsonObject.optBoolean(key);
                                    TcpClient.getInstance().putAllIp(key, value);
                                }
                            }
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            } else {
                if (!TextUtils.isEmpty(date)) {
                    TcpClient.getInstance().disconnect(date);
                }
            }
        }
    }

    /**
     * 断开连接
     *
     * @param all_ip
     */
    public void disconnect(String all_ip) {
        Preconditions.checkNotNull(mContext, "TcpClient disconnect Context isNull");
        if (CommonUtils.Available(mContext)) {
            if (!TextUtils.isEmpty(all_ip)) {
                try {
                    Iterator<Channel> iterator = NettyConfig.client_group.iterator();
                    while (iterator.hasNext()) {
                        Channel channel = iterator.next();
                        String desc_ip = channel.remoteAddress().toString();
                        if (desc_ip.contains(all_ip)) {
                            NettyConfig.client_group.remove(channel);
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 重连
     *
     * @param hostIp 连接IP地址
     */
    public synchronized void reconnection(final String hostIp) {
        executorService.execute(new Runnable() {
            @Override
            public void run() {
                TcpClient.getInstance().connect(hostIp);
            }
        });
    }

}
